package com.postracker.initdatabase.io.csv;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringUtils;

import au.com.bytecode.opencsv.CSVReader;

import com.postracker.initdatabase.io.Table;
import com.postracker.initdatabase.io.exception.FileException;
import com.postracker.initdatabase.util.CollectionUtils;

class BufferedTableCsvFile implements FileBasedTable {

	private static final String FILE_EXT = "csv";
	private static final String VALID_FILE_REGEX = ".+\\.(" + FILE_EXT + ")$";
	private CSVReader csvReader;
	private List<String[]> allRows;
	private File file;

	protected BufferedTableCsvFile() {
	}

	private boolean isInvalidFileExtension() {
		return !file.getPath().matches(VALID_FILE_REGEX);
	}

	private void loadCsvReader() {
		try {
			allRows = null;
			FileReader fileReader = new FileReader(file);
			csvReader = new CSVReader(fileReader);
		} catch (FileNotFoundException e) {
			throw new FileException(e);
		}
	}

	@Override
	public Table getTable() {
		return new BasicTable(getRows(), getFileNameWithoutExtension());
	}

	private List<String[]> getRows() {
		if (contentNotBuffered()) {
			loadAllRows();
		}
		return CollectionUtils.cloneList(allRows);
	}

	private boolean contentNotBuffered() {
		return allRows == null;
	}

	private void loadAllRows() {
		try {
			readAllRows();
		} catch (IOException e) {
			throw new FileException(e);
		}
	}

	private void readAllRows() throws IOException {
		allRows = new ArrayList<String[]>();
		Iterator<String[]> iterator = csvReader.readAll().iterator();
		while (iterator.hasNext()) {
			allRows.add(iterator.next());
		}
	}

	private String getFileNameWithoutExtension() {
		String fileName = file.getName();
		int extensionIndex = StringUtils.lastIndexOf(fileName, FILE_EXT);
		return StringUtils.substring(fileName, 0, extensionIndex - 1);
	}

	@Override
	public void setFile(File file) {
		this.file = file;
		assertValidFile();
		loadCsvReader();
	}

	private void assertValidFile() {
		if (isInvalidFileExtension()) {
			throw new FileException("Invalid file extension");
		}
	}
}